package com.settlement.system.job;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.settlement.system.common.constant.SystemConstants;
import com.settlement.system.common.enums.AccountingStatusEnum;
import com.settlement.system.common.enums.AuditErrorRecordTypeEnum;
import com.settlement.system.common.enums.BillStatusEnum;
import com.settlement.system.common.model.QyWechatData;
import com.settlement.system.common.util.DateUtils;
import com.settlement.system.common.util.HttpUtils;
import com.settlement.system.mapper.SysBillMapper;
import com.settlement.system.mapper.SysOrderMapper;
import com.settlement.system.model.entity.*;
import com.settlement.system.model.query.AuditErrorRecordQuery;
import com.settlement.system.model.query.BillPageQuery;
import com.settlement.system.model.query.KafkaSendErrorRecordQuery;
import com.settlement.system.model.vo.StoreVO;
import com.settlement.system.service.*;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
public class JobUtils {

    private final Logger logger = LoggerFactory.getLogger(JobUtils.class);

    private final SysFileAuditService fileAuditService;

    private final SysBillService sysBillService;

    private final SysBillSummaryService sysBillSummaryService;

    private final SysStoreService sysStoreService;

    private final SysPlatformService sysPlatformService;

    private final SysAccessoryService accessoryService;

    private final SysBillMapper sysBillMapper;

    private final SysOrderMapper sysOrderMapper;

    private final AuditErrorRecordService auditErrorRecordService;

    private final WebHookService webHookService;

    private final SysAuditService auditService;

    private final KafkaSendErrorRecordService kafkaSendErrorRecordService;

    /**
     * 5分钟检查一次，是否存在kafka发送失败的记录
     */
    @Scheduled(cron = "0 0/5 * * * ?")
    public void checkKafkaSendErrorRecord() {
        KafkaSendErrorRecordQuery queryParams = new KafkaSendErrorRecordQuery();
        Page<KafkaSendErrorRecord> page = kafkaSendErrorRecordService.getPage(queryParams);
        if(page.getRecords().size() > 0){
            List<WebHook> webHooks = webHookService.list();
            String content = "慕迪消息队列提醒：\n" +
                    "错误信息：<font color=\"comment\">%s</font>\n".formatted("存在消息队列发送失败的记录") +
                    "<font color=\"warning\">请立即查看</font>\n";
            QyWechatData qyWechatData = new QyWechatData(content);
            for (WebHook webHook : webHooks) {
                if (SystemConstants.WECHAT.equals(webHook.getHookType())) {
                    HttpUtils.sendToQyWechat(qyWechatData, webHook.getWebHookUrl());
                }
            }
        }
    }


    /**
     * 5分钟检查一次，查看核销单记录表是否存在数据，如果存在需要告警
     */
    @Scheduled(cron = "0 0/5 * * * ?")
    public void checkAuditErrorRecord() {
        AuditErrorRecordQuery queryParams = new AuditErrorRecordQuery();
        queryParams.setPageSize(100);
        Page<AuditErrorRecord> page = auditErrorRecordService.getPage(queryParams);
        boolean hasError = false;
        if(page.getRecords().size() > 0){
            if(page.getRecords().stream().anyMatch(item -> Objects.nonNull(item.getTryNumber()) && item.getTryNumber() >= 3)){
                // 已经重试了3次，还是不成功，就代表有问题
                hasError = true;
            }
            SysStore store;
            SysPlatform platform;
            SysOrder order;
            boolean isSuccess;
            List<AuditErrorRecord> needUpdateList = new ArrayList<>();
            // 重新尝试生成核销单
            for (AuditErrorRecord record : page.getRecords()) {
                logger.info("正在尝试重新转换核销单：【{}】", record);
                // 更新操作时间
                record.setUpdateTime(LocalDateTime.now());
                store = sysStoreService.getById(record.getStoreId());
                if(Objects.isNull(store)){
                    record.setTryNumber(record.getTryNumber() + 1);
                    logger.error("店铺为空【{}】", record.getStoreId());
                    addToList(needUpdateList, record);
                    continue;
                }
                platform = sysPlatformService.getByPlatformKey(store.getStoreKey());
                if(Objects.isNull(platform)){
                    record.setTryNumber(record.getTryNumber() + 1);
                    logger.error("平台为空【{}】", store.getStoreKey());
                    addToList(needUpdateList, record);
                    continue;
                }
                if(Objects.equals(AuditErrorRecordTypeEnum.ORDER.getValue(), record.getDataType())){
                    order = sysOrderMapper.getOrderById("sys_order_%s".formatted(record.getDataId().substring(0, 6)), record.getDataId());
                    if(Objects.isNull(order)){
                        logger.error("找不到标准订单【{}】", record.getDataId());
                        record.setTryNumber(record.getTryNumber() + 1);
                        addToList(needUpdateList, record);
                        continue;
                    }
                    // 重试
                    isSuccess = auditService.convert(order, platform, store);
                    if(isSuccess){
                        logger.info("重新转换核销单【{}】成功", record.getDataId());
                        record.setDeleted(1);
                        addToList(needUpdateList, record);
                    }
                }else if(Objects.equals(AuditErrorRecordTypeEnum.BILL.getValue(), record.getDataType())){
                    // 重试
                    List<LocalDateTime> businessDateList = new ArrayList<>();
                    if(StringUtils.hasText(record.getBusinessDateStr())){
                        for (String text : record.getBusinessDateStr().split(",")) {
                            LocalDateTime localDateTime = DateUtils.convert(text);
                            if(Objects.nonNull(localDateTime)){
                                businessDateList.add(localDateTime);
                            }
                        }
                    }
                    isSuccess = auditService.convert(record.getDataId(), businessDateList, platform, store, Objects.equals(record.getNeedUpdateBusinessDate(), 1));
                    if(isSuccess){
                        logger.info("重新转换核销单【{}】成功", record.getDataId());
                        record.setDeleted(1);
                        addToList(needUpdateList, record);
                    }
                }else if(Objects.equals(AuditErrorRecordTypeEnum.AUDIT.getValue(), record.getDataType())){
                    isSuccess = auditService.reBill(Collections.singletonList(record.getDataId()));
                    if(isSuccess){
                        logger.info("重新转换核销单【{}】成功", record.getDataId());
                        record.setDeleted(1);
                        addToList(needUpdateList, record);
                    }
                }
            }
            if(needUpdateList.size() > 0){
                logger.info("有【{}】条记录需要更新...", needUpdateList.size());
                auditErrorRecordService.updateBatchById(needUpdateList);
                logger.info("【{}】条记录需要更新成功...", needUpdateList.size());
            }
        }
        if (hasError) {
            List<WebHook> webHooks = webHookService.list();
            String content = "嗨玩够核销单提醒：\n" +
                    "错误信息：<font color=\"comment\">%s</font>\n".formatted("存在核销单转换失败的记录") +
                    "<font color=\"warning\">请立即查看</font>\n";
            QyWechatData qyWechatData = new QyWechatData(content);
            for (WebHook webHook : webHooks) {
                if (SystemConstants.WECHAT.equals(webHook.getHookType())) {
                    HttpUtils.sendToQyWechat(qyWechatData, webHook.getWebHookUrl());
                }
            }
        }
    }

    private void addToList(List<AuditErrorRecord> list, AuditErrorRecord record){
        // 检查列表是否已经存在
        if(list.stream().noneMatch(item -> Objects.equals(item.getId(), record.getId()))){
            // 不存在，添加
            list.add(record);
        }
    }

    // 每日凌晨1点自动生成下个月的归档核销表
    @Scheduled(cron = "0 0 1 * * ?")
    public void checkTable() {
        String nextMonth = DateUtils.formatDate(LocalDateTime.now().plusMonths(1));
        // 标准核销单
        String tableName = "sys_file_audit_%s".formatted(nextMonth);
        if (!fileAuditService.existTable(tableName)) {
            fileAuditService.createTable(tableName);
        }
        // 标准账单
        tableName = "sys_bill_%s".formatted(nextMonth);
        if (!fileAuditService.existTable(tableName)) {
            sysBillMapper.createTable(tableName);
        }
        // 标准订单
        tableName = "sys_order_%s".formatted(nextMonth);
        if (!fileAuditService.existTable(tableName)) {
            sysOrderMapper.createTable(tableName);
        }
    }

    // 每月1号的1点执行生成上个月的汇总账单
    @Scheduled(cron = "0 0 1 1 * ?")
    public void createMonthBill() {
        // 辅助项
        List<SysAccessory> sysAccessoryList = accessoryService.findAll();
        if (sysAccessoryList.size() == 0) {
            return;
        }
        // 所有店铺
        List<StoreVO> allStore = sysStoreService.getAllStore();
        // 所有平台
        List<SysPlatform> platforms = sysPlatformService.list();
        // 上月
        String lastMonth = DateUtils.formatDate(LocalDateTime.now().minusMonths(1));
        String tableName = "sys_bill_summary_%s".formatted(lastMonth);
        if (!fileAuditService.existTable(tableName)) {
            // 先清空数据
            sysBillSummaryService.removeAll(tableName);
        } else {
            sysBillSummaryService.createTable(tableName);
        }
        // 遍历查出所有的数据
        BillPageQuery queryParams = new BillPageQuery();
        // 每次查3000条数据
        queryParams.setPageSize(3000);
        queryParams.setBillMonth(lastMonth);
        queryParams.setTableName("sys_bill_%s".formatted(lastMonth));
        Page<SysBill> billPage = sysBillService.getAllBillPage(queryParams);
        // 过滤不参与记账的数据
        List<SysBill> sysBillList = billPage.getRecords().stream().filter(sysBill -> AccountingStatusEnum.YES.getValue().equals(sysBill.getAccounting())).toList();
        while (sysBillList.size() > 0) {
            for (SysBill sysBill : sysBillList) {
                // 拼接辅助项字段，用于汇总标准账单
                sysBill.setAccessoryText(concatStr(sysBill, sysAccessoryList.get(0)));
            }
            // 需要创建或者更新的数据
            List<SysBillSummary> sysBillSummaryList = new ArrayList<>();
            // 处理这一批的数据
            // 先汇总一次 按店铺+记账项目+辅助项
            Map<String, List<SysBill>> collect =
                    sysBillList.stream().collect(Collectors.groupingBy(sysBill -> sysBill.getStoreId() + sysBill.getBillProject() + sysBill.getAccessoryText()));
            collect.forEach((key, data) -> {
                SysBillSummary billSummary = new SysBillSummary();
                BeanUtil.copyProperties(data.get(0), billSummary, "id");
                // 清空账单数据金额
                billSummary.setBillAmount(BigDecimal.ZERO);
                billSummary.setTaxAmount(BigDecimal.ZERO);
                billSummary.setUnTaxAmount(BigDecimal.ZERO);
                billSummary.setTableName(tableName);
                billSummary.setAccessoryText(data.get(0).getAccessoryText());
                // 辅助项
                billSummary.setAccessory(data.get(0).getAccessory());
                // 统一账单汇总ID
                billSummary.setSysBillId("HZZD_%s_%s".formatted(data.get(0).getBillSystemPlatformCode(), DateUtils.getDateString()));
                // 渠道编码
                // 通过平台Key找到平台
                allStore.stream().filter(storeVO -> storeVO.getId().equals(data.get(0).getStoreId()))
                        .findFirst().flatMap(storeVO -> platforms.stream().filter(platform -> platform.getPlatformKey().equals(storeVO.getStoreKey()))
                                .findFirst()).ifPresent(platform -> {
                            // 对账系统平台编码
                            billSummary.setChannelCode(platform.getReconciliationSystemCode());
                            billSummary.setChannel(platform.getReconciliationSystemName());
                        });
                // 会计期间
                billSummary.setBillDate(data.get(0).getSysBillDate());
                // 店铺ID
                billSummary.setStoreId(data.get(0).getStoreId());
                // 店铺编码
                billSummary.setShopCode(data.get(0).getCommercePlatformStoreCode());
                // 店铺名称
                billSummary.setShopName(data.get(0).getCommercePlatformStoreName());
                // 入账主体
                billSummary.setReceiveCompany(data.get(0).getCompanyCode());
                // 汇总账单金额
                for (SysBill datum : data) {
                    if (datum.getBillAmount() != null) {
                        billSummary.setBillAmount(billSummary.getBillAmount().add(datum.getBillAmount()).setScale(6, RoundingMode.UP));
                    }
                }
                if (billSummary.getTaxAmount() == null) {
                    billSummary.setTaxAmount(BigDecimal.ZERO);
                }
                // 汇总税额
                for (SysBill datum : data) {
                    if (datum.getTaxAmount() != null) {
                        billSummary.setTaxAmount(billSummary.getTaxAmount().add(datum.getTaxAmount()).setScale(6, RoundingMode.UP));
                    }
                }
                // 不含税金额
                billSummary.setUnTaxAmount(billSummary.getBillAmount().subtract(billSummary.getTaxAmount()).setScale(6, RoundingMode.UP));
                sysBillSummaryList.add(billSummary);
                // 反写汇总ID
                for (SysBill sysBill : data) {
                    sysBill.setSummaryId(billSummary.getSysBillId());
                    // 需要更新的表
                    sysBill.setTableName(queryParams.getTableName());
                    // 修改已入账
                    sysBill.setStatus(BillStatusEnum.YES.getValue());
                    sysBillService.updateBill(sysBill);
                }
            });
            sysBillSummaryService.createOrUpdate(sysBillSummaryList);
            // 继续查下一页
            queryParams.setPageNum(queryParams.getPageNum() + 1);
            billPage = sysBillService.getAllBillPage(queryParams);
            // 过滤不参与记账的数据
            sysBillList = billPage.getRecords().stream().filter(sysBill -> AccountingStatusEnum.YES.getValue().equals(sysBill.getAccounting())).toList();
        }
    }

    private String concatStr(SysBill sysBill, SysAccessory sysAccessory) {
        List<String> assessoryList = new ArrayList<>();
        if (StringUtils.hasText(sysBill.getAccessory())) {
            Map<String, Object> map = JSONObject.parseObject(sysBill.getAccessory(), Map.class);
            if (StringUtils.hasText(sysAccessory.getAccessoryName1()) && map.get(sysAccessory.getAccessoryName1()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName1()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName2()) && map.get(sysAccessory.getAccessoryName2()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName2()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName3()) && map.get(sysAccessory.getAccessoryName3()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName3()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName4()) && map.get(sysAccessory.getAccessoryName4()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName4()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName5()) && map.get(sysAccessory.getAccessoryName5()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName5()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName6()) && map.get(sysAccessory.getAccessoryName6()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName6()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName7()) && map.get(sysAccessory.getAccessoryName7()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName7()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName8()) && map.get(sysAccessory.getAccessoryName8()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName8()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName9()) && map.get(sysAccessory.getAccessoryName9()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName9()));
            }
        }
        return String.join(",", assessoryList);
    }

    public static String concatOtherAccessoryStr(SysBill sysBill, SysAccessory sysAccessory) {
        List<String> assessoryList = new ArrayList<>();
        if (StringUtils.hasText(sysBill.getOtherAccessory())) {
            Map<String, Object> map = JSONObject.parseObject(sysBill.getOtherAccessory(), Map.class);
            if (StringUtils.hasText(sysAccessory.getAccessoryName1()) && map.get(sysAccessory.getAccessoryName1()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName1()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName2()) && map.get(sysAccessory.getAccessoryName2()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName2()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName3()) && map.get(sysAccessory.getAccessoryName3()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName3()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName4()) && map.get(sysAccessory.getAccessoryName4()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName4()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName5()) && map.get(sysAccessory.getAccessoryName5()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName5()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName6()) && map.get(sysAccessory.getAccessoryName6()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName6()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName7()) && map.get(sysAccessory.getAccessoryName7()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName7()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName8()) && map.get(sysAccessory.getAccessoryName8()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName8()));
            }
            if (StringUtils.hasText(sysAccessory.getAccessoryName9()) && map.get(sysAccessory.getAccessoryName9()) != null) {
                assessoryList.add((String) map.get(sysAccessory.getAccessoryName9()));
            }
        }
        return String.join(",", assessoryList);
    }

    public void testGenerateBillSummary(String billMonth) {
        // 辅助项
        List<SysAccessory> sysAccessoryList = accessoryService.findAll();
        if (sysAccessoryList.size() == 0) {
            return;
        }
        // 所有店铺
        List<StoreVO> allStore = sysStoreService.getAllStore();
        // 所有平台
        List<SysPlatform> platforms = sysPlatformService.list();
        String tableName = "sys_bill_summary_%s".formatted(billMonth);
        if (fileAuditService.existTable(tableName)) {
            // 先清空数据
            sysBillSummaryService.removeAll(tableName);
        } else {
            sysBillSummaryService.createTable(tableName);
        }
        // 遍历查出所有的数据
        BillPageQuery queryParams = new BillPageQuery();
        // 每次查500条数据
        queryParams.setPageSize(500);
        queryParams.setBillMonth(billMonth);
        queryParams.setTableName("sys_bill_%s".formatted(billMonth));
        Page<SysBill> billPage = sysBillService.getAllBillPage(queryParams);
        // 过滤不参与记账的数据
        List<SysBill> sysBillList;
        while (billPage.getRecords().size() > 0) {
            sysBillList = billPage.getRecords().stream().filter(sysBill -> AccountingStatusEnum.YES.getValue().equals(sysBill.getAccounting())).toList();
            for (SysBill sysBill : sysBillList) {
                // 拼接辅助项字段，用于汇总标准账单
                sysBill.setAccessoryText(concatStr(sysBill, sysAccessoryList.get(0)));
            }
            // 需要创建或者更新的数据
            List<SysBillSummary> sysBillSummaryList = new ArrayList<>();
            // 处理这一批的数据
            // 先汇总一次 按店铺+记账项目+辅助项
            Map<String, List<SysBill>> collect =
                    sysBillList.stream().collect(Collectors.groupingBy(sysBill -> sysBill.getStoreId() + sysBill.getBillProject() + sysBill.getAccessoryText()));
            collect.forEach((key, data) -> {
                SysBillSummary billSummary = new SysBillSummary();
                BeanUtil.copyProperties(data.get(0), billSummary);
                // 清空账单数据金额
                billSummary.setBillAmount(BigDecimal.ZERO);
                billSummary.setTaxAmount(BigDecimal.ZERO);
                billSummary.setUnTaxAmount(BigDecimal.ZERO);
                billSummary.setTableName(tableName);
                billSummary.setAccessoryText(data.get(0).getAccessoryText());
                // 辅助项
                billSummary.setAccessory(data.get(0).getAccessory());
                // 统一账单汇总ID
                billSummary.setSysBillId("HZZD_%s_%s".formatted(data.get(0).getBillSystemPlatformCode(), DateUtils.getDateString()));
                // 通过平台Key找到平台
                allStore.stream().filter(storeVO -> storeVO.getId().equals(data.get(0).getStoreId()))
                        .findFirst().flatMap(storeVO -> platforms.stream().filter(platform -> platform.getPlatformKey().equals(storeVO.getStoreKey()))
                                .findFirst()).ifPresent(platform -> {
                            // 对账系统平台编码
                            billSummary.setChannelCode(platform.getReconciliationSystemCode());
                            billSummary.setChannel(platform.getReconciliationSystemName());
                        });
                // 会计期间
                billSummary.setBillDate(data.get(0).getSysBillDate());
                // 店铺ID
                billSummary.setStoreId(data.get(0).getStoreId());
                // 店铺编码
                billSummary.setShopCode(data.get(0).getCommercePlatformStoreCode());
                // 店铺名称
                billSummary.setShopName(data.get(0).getCommercePlatformStoreName());
                // 入账主体
                billSummary.setReceiveCompany(data.get(0).getCompanyCode());
                // 汇总账单金额
                for (SysBill datum : data) {
                    if (datum.getBillAmount() != null) {
                        billSummary.setBillAmount(billSummary.getBillAmount().add(datum.getBillAmount()).setScale(6
                                , RoundingMode.UP));
                    }
                }
                if (billSummary.getTaxAmount() == null) {
                    billSummary.setTaxAmount(BigDecimal.ZERO);
                }
                // 汇总税额
                for (SysBill datum : data) {
                    if (datum.getTaxAmount() != null) {
                        billSummary.setTaxAmount(billSummary.getTaxAmount().add(datum.getTaxAmount()).setScale(6
                                , RoundingMode.UP));
                    }
                }
                // 不含税金额
                billSummary.setUnTaxAmount(billSummary.getBillAmount().subtract(billSummary.getTaxAmount()).setScale(6
                        , RoundingMode.UP));
                sysBillSummaryList.add(billSummary);
                // 反写汇总ID
                for (SysBill sysBill : data) {
                    sysBill.setSummaryId(billSummary.getSysBillId());
                    // 需要更新的表
                    sysBill.setTableName(queryParams.getTableName());
                    sysBill.setStatus(BillStatusEnum.YES.getValue());
                    sysBillService.updateBill(sysBill);
                }
            });
            sysBillSummaryService.createOrUpdate(sysBillSummaryList);
            // 继续查下一页
            queryParams.setPageNum(queryParams.getPageNum() + 1);
            billPage = sysBillService.getAllBillPage(queryParams);
        }
    }
}
